package joc.internal.transformer;

import javassist.CtBehavior;
import javassist.CtClass;
import javassist.CtMethod;
import joc.AfterHook;
import joc.BeforeHook;
import joc.internal.compiler.EmptyExp;
import joc.internal.compiler.StandaloneExp;

public abstract class CustomHookBehaviorTransformer extends DeclaredBehaviorTransformer {

	public CustomHookBehaviorTransformer(Transformer transformer) {
		super(transformer);
	}

	protected void applyHook(CtBehavior behavior, String hookClassName, String id) throws Exception {
		getLogger().info("behavior " + behavior.getLongName() + " has pre-hook " + hookClassName);
		CtClass annotationClass = transformer.getPool().get(hookClassName);
		StandaloneExp insertBefore = initializeConditionString(hookClassName);
		StandaloneExp insertAfter = new EmptyExp();
		for (CtMethod preHookMethod : annotationClass.getDeclaredMethods()) {
			String hookId = getHookIdFromHookMethod(preHookMethod);
			if (hookId != null && hookId.equals(id)) {
				if (preHookMethod.hasAnnotation(BeforeHook.class)) {
					insertBefore = insertBefore.append(callConditionString(annotationClass, preHookMethod, false,
							behavior, false));
				} else {
					insertAfter = insertAfter.append(callConditionString(annotationClass, preHookMethod, false,
							behavior, true));
				}
			}
		}
		getLogger().info("insertBefore: " + insertBefore);
		getLogger().info("insertAfter: " + insertAfter);
		insertBefore.insertBefore(behavior);
		insertAfter.insertAfter(behavior);
	}

	private String getHookIdFromHookMethod(CtMethod preHookMethod) throws ClassNotFoundException {
		String hookId = null;
		if (preHookMethod.hasAnnotation(BeforeHook.class)) {
			BeforeHook hookAnnotation = (BeforeHook) preHookMethod.getAnnotation(BeforeHook.class);
			hookId = hookAnnotation.value();
		} else if (preHookMethod.hasAnnotation(AfterHook.class)) {
			AfterHook hookAnnotation = (AfterHook) preHookMethod.getAnnotation(AfterHook.class);
			hookId = hookAnnotation.value();
		}
		return hookId;
	}

}
